#ifndef _NE_TIMER_H_
#define _NE_TIMER_H_

#include <neinit.h>

#if NE_PLATFORM == NE_PLATFORM_WINDOWS
#include <windows.h>
#else
#include <sys/time.h>
#endif

namespace ne
{
    /* TODO: TimeInfo
        Member     Meaning                   Range
        tm_sec     seconds after the minute  0-61*
        tm_min     minutes after the hour    0-59
        tm_hour    hours since midnight      0-23
        tm_mday    day of the month          1-31
        tm_mon     months since January      0-11
        tm_year    years since 1900    
        tm_wday    days since Sunday         0-6
        tm_yday    days since January 1      0-365
        tm_isdst   Daylight Saving Time flag        
    */

    /* TODO: Time format
        Specifier   Replaced by ------ Example
        %a          Abbreviated weekday name * ------ Thu
        %A          Full weekday name * ------ Thursday
        %b          Abbreviated month name * ------ Aug
        %B          Full month name * ------ August
        %c          Date and time representation * %x %X ------ 08/23/01 14:55:02
        %d          Day of the month (01-31) ------ 23
        %H          Hour in 24h format (00-23) ------ 14
        %I          Hour in 12h format (01-12) ------ 02
        %j          Day of the year (001-366) ------ 235
        %m          Month as a decimal number (01-12) ------ 08
        %M          Minute (00-59) ------ 55
        %p          AM or PM designation ------ PM
        %S          Second (00-61) ------ 02
        %U          Week number with the first Sunday as the first day of week one (00-53) ------ 33
        %w          Weekday as a decimal number with Sunday as 0 (0-6) ------ 4
        %W          Week number with the first Monday as the first day of week one (00-53) ------ 34
        %x          Date representation * %m/%d/%y ------ 08/23/01
        %X          Time representation * %H/%M/%S ------ 14:55:02
        %y          Year, last two digits (00-99) ------ 01
        %Y          Year ------ 2001
        %Z          Timezone name or abbreviation ------ CDT
        %%          A % sign ------ %
    */

    typedef tm TimeInfo;

#if NE_PLATFORM != NE_PLATFORM_WINDOWS
    typedef timeval TimeValue;
#endif

    class NEAPI Timer
    {
        public:
            Timer();

            double getIntervalSeconds()
            {
                return getIntervalMilliseconds() * 0.001;
            }

            double getIntervalMilliseconds();

            double getIntervalMicroseconds()
            {
                return getIntervalMilliseconds() * 1000;
            }

            double getIntervalSecondsCPU()
            {
                return getIntervalMillisecondsCPU() * 0.001;
            }

            double getIntervalMillisecondsCPU();

            double getIntervalMicrosecondsCPU()
            {
                return getIntervalMicrosecondsCPU() * 1000;
            }

            void reset();

            double getSeconds();

            double getMilliseconds();

            double getMicroseconds();

            double getSecondsCPU();

            double getMillisecondsCPU()
            {
                return getSecondsCPU() * 1000;
            }

            double getMicrosecondsCPU()
            {
                return getSecondsCPU() * 1000000;
            }

            ~Timer();

        private:
            Timer(const Timer &);

            Timer& operator = (const Timer &);

        public:
            // TODO: Format = [%a %b %d %X %Y] [Fri Nov 04 16:12:45 2011]
            static std::string GetTimeString();
            static std::string GetTimeString(const std::string &format);
            static std::string GetMillisecondsString();
            static const TimeInfo* GetTimeInfo();

        private:
#if NE_PLATFORM == NE_PLATFORM_WINDOWS
            LARGE_INTEGER mZeroTime;
            LARGE_INTEGER mFrequency;
            DWORD mStartTick;
            double mLast;
            DWORD_PTR mMask;
#else
            TimeValue mZeroTime;
#endif
            double mLastTime;
            double mNewTime;
            clock_t mZeroClock;
            double mLastClock;
            double mNewClock;
    };
}

#endif
